﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Data;

namespace AMS.Configuration
{
    /// <summary>
    /// 列表的配置信息
    /// </summary>
    public class ListConfigInfo
    {
        /// <summary>
        /// 节点名
        /// </summary>
        public string SectionName { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string Title { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string ColumnFormat { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string CaptionFormat { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string DisplayFormat { get; set; }
        /// <summary>
        /// 显示的列
        /// </summary>
        public string DisplayCaptionFormat { get; set; }
        /// <summary>
        /// 导出的列
        /// </summary>
        public string ExportFormat { get; set; }
        /// <summary>
        /// 导出的列
        /// </summary>
        public string ExportCaptionFormat { get; set; }

        private const string ColumnPattern = @"\{\[\w+\s*(\,\s*\d+)?\]\}";

        private List<ColumnInfo> displayColumns;
        /// <summary>
        /// 显示的列信息
        /// </summary>
        public List<ColumnInfo> DisplayColumns
        {
            get
            {
                if (displayColumns == null)
                {
                    displayColumns = ParseDisplayColumns();
                }

                return displayColumns;
            }
        }

        private List<ColumnInfo> exportColumns;
        /// <summary>
        /// 导出的列信息
        /// </summary>
        public List<ColumnInfo> ExportColumns
        {
            get
            {
                if (exportColumns == null)
                {
                    exportColumns = ParseExportColumns();
                }

                return exportColumns;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public List<ColumnInfo> GetAllColumns()
        {
            string[] columnNames = ColumnFormat.Split('|');
            string[] captions = CaptionFormat.Split('|');
            string[] displayNames = null;
            Dictionary<string, int> displayDictKeys = null;
            if (!string.IsNullOrEmpty(DisplayFormat))
            {
                ParseDisplayColumns(DisplayFormat, out displayNames, out displayDictKeys);
            }

            List<ColumnInfo> columns = new List<ColumnInfo>();
            for (int i = 0; i < columnNames.Length - 1; i++)
            {
                ColumnInfo column = new ColumnInfo(columnNames[i]);
                column.Caption = captions[i];
                if (displayNames != null && displayNames.Length > 0)
                {
                    int index = Array.IndexOf<string>(displayNames, columnNames[i]);
                    if (index >= 0)
                    {
                        column.IsDisplayColumn = true;

                        if (displayDictKeys.ContainsKey(columnNames[index]))
                        {
                            column.DictKey = displayDictKeys[columnNames[index]];
                        }
                    }
                }

                columns.Add(column);
            }

            return columns;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        [Obsolete]
        public List<ColumnInfo> GetDisplayColumns()
        {
            if (string.IsNullOrEmpty(DisplayFormat))
            {
                return GetAllColumns();
            }

            string displayFormat = DisplayFormat;
            string[] displayNames = null;
            Dictionary<string, int> displayDictKeys = null;
            ParseDisplayColumns(displayFormat, out displayNames, out displayDictKeys);
            string[] columnNames = ColumnFormat.Split('|');
            string[] captions = CaptionFormat.Split('|');

            List<ColumnInfo> columns = new List<ColumnInfo>();
            for (int i = 0; i < displayNames.Length - 1; i++)
            {
                string displayName = displayNames[i];
                ColumnInfo column = new ColumnInfo();
                int index = Array.IndexOf<string>(columnNames, displayName);
                column.Name = displayName;
                column.Caption = captions[index];
                column.IsDisplayColumn = true;
                if (displayDictKeys.ContainsKey(displayName))
                {
                    column.DictKey = displayDictKeys[displayName];
                }

                columns.Add(column);
            }

            return columns;
        }

        /// <summary>
        /// 解析显示列
        /// </summary>
        /// <returns></returns>
        public List<ColumnInfo> ParseDisplayColumns()
        {
            if (string.IsNullOrEmpty(DisplayFormat))
            {
                displayColumns = GetAllColumns();
                return displayColumns;
            }

            return ParseColumnsByCategory(DisplayFormat, DisplayCaptionFormat);
        }

        /// <summary>
        /// 解析导出列
        /// </summary>
        /// <returns></returns>
        public List<ColumnInfo> ParseExportColumns()
        {
            if (string.IsNullOrEmpty(ExportFormat))
            {
                exportColumns = GetAllColumns();
                return exportColumns;
            }

            return ParseColumnsByCategory(ExportFormat, ExportCaptionFormat);
        }

        /// <summary>
        /// 通用将列格式信息转换成列信息的函数
        /// </summary>
        /// <param name="categoryNameFormat">not null</param>
        /// <param name="categoryCaptionFormat">nullable</param>
        /// <returns></returns>
        private List<ColumnInfo> ParseColumnsByCategory(string categoryNameFormat, string categoryCaptionFormat)
        {
            string[] columnNames = ColumnFormat.Split('|');
            string[] captions = CaptionFormat.Split('|');
            string[] names = categoryNameFormat.Split('|');
            string[] displayCaptions = null;
            if (!string.IsNullOrEmpty(categoryCaptionFormat))
            {
                displayCaptions = categoryCaptionFormat.Split('|');
            }

            List<ColumnInfo> columns = new List<ColumnInfo>();
            for (int i = 0; i < names.Length - 1; i++)
            {
                ColumnInfo column = ParseColumn(names[i]);
                if (displayCaptions == null || displayCaptions.Length == 0)
                {
                    int index = Array.IndexOf<string>(columnNames, column.Name);
                    column.Caption = captions[index];
                }
                else
                {
                    column.Caption = displayCaptions[i];
                }

                columns.Add(column);
            }

            return columns;
        }

        /// <summary>
        /// 解析列，但不解析如列标题等信息
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        private ColumnInfo ParseColumn(string expression)
        {
            ColumnInfo column;
            if (!expression.Contains(",") && !expression.Contains(";"))
            {
                column = new ColumnInfo();
                column.Name = expression;
                return column;
            }

            string[] tokens;
            if (!expression.Contains(";"))
            {
                // 形如：Sex, 3
                column = new ColumnInfo();
                tokens = expression.Split(',');
                column.Name = tokens[0].Trim();
                column.DictKey = int.Parse(tokens[1].Trim());
                return column;
            }

            // 形如: Sex, 3; width=100
            // 或组合列
            tokens = expression.Split(';');
            if (tokens[0].Contains("{[") && tokens[0].Contains("]}"))
            {
                // 组合列
                column = ParseCompoundColumn(tokens);
            }
            else
            {
                // 非组合列
                column = ParseSimpleColumn(tokens);
            }

            return column;
        }

        /// <summary>
        /// 解析简单列
        /// </summary>
        /// <param name="columnParts"></param>
        /// <returns></returns>
        private ColumnInfo ParseSimpleColumn(string[] columnParts)
        {
            ColumnInfo column = new ColumnInfo();
            string[] tokens = columnParts[0].Split(',');
            column.Name = tokens[0].Trim();
            if (tokens.Length > 1)
            {
                column.DictKey = int.Parse(tokens[1].Trim());
            }

            ParseColumnExceptFirstPart(column, columnParts);
            return column;
        }

        /// <summary>
        /// 解析组合列
        /// </summary>
        /// <param name="columnParts"></param>
        /// <returns></returns>
        private CompoundColumnInfo ParseCompoundColumn(string[] columnParts)
        {
            // first part
            CompoundColumnInfo column = new CompoundColumnInfo();
            ParseColumnExceptFirstPart(column, columnParts);
            if (string.IsNullOrEmpty(column.Name))
            {
                throw new ConfigException("组合列必需包括name属性");
            }


            MatchCollection matches = Regex.Matches(columnParts[0], ColumnPattern);
            if (matches.Count == 0)
            {
                column.Format = columnParts[0];
                return column;
            }

            ColumnInfo subColumn;
            foreach (Match item in matches)
            {
                if (item.Groups.Count == 1)
                {
                    // 不带字典的
                    subColumn = new ColumnInfo();
                    subColumn.Name = item.Value.Substring(2, item.Value.Length - 4);
                    column.SubColumns.Add(subColumn);
                }
                else
                {
                    // 带字典的
                    string[] tokens = item.Value.Substring(2, item.Value.Length - 4).Split(',');
                    subColumn = new ColumnInfo();
                    subColumn.Name = tokens[0].Trim();
                    subColumn.DictKey = int.Parse(tokens[1].Trim());
                    column.SubColumns.Add(subColumn);
                }
            }

            string spattern = columnParts[0];
            for (int i = matches.Count - 1; i >= 0; i--)
            {
                spattern = spattern.Remove(matches[i].Index, matches[i].Length).Insert(matches[i].Index, "{" + i.ToString() + "}");
            }

            column.Format = spattern;
            return column;
        }

        /// <summary>
        /// 解析子域信息，除了第一个子域外
        /// </summary>
        /// <param name="column"></param>
        /// <param name="columnParts"></param>
        private void ParseColumnExceptFirstPart(ColumnInfo column, string[] columnParts)
        {
            for (int i = 1; i < columnParts.Length; i++)
            {
                if (string.IsNullOrEmpty(columnParts[i].Trim()))
                {
                    continue;
                }

                int index = columnParts[i].IndexOf('=');
                if (index < 0)
                {
                    throw new ConfigException("配置错误，除了第一个域名，每个域需要是 键=值 的样式");
                }

                string key = columnParts[i].Substring(0, index).Trim();
                string value = columnParts[i].Substring(index + 1).Trim();
                if (string.Equals(key, "width", StringComparison.InvariantCultureIgnoreCase))
                {
                    column.Width = int.Parse(value.Trim());
                }
                else if (string.Equals(key, "align", StringComparison.InvariantCultureIgnoreCase))
                {
                    column.HAlign = (HorizenAlignment)("+LMR".IndexOf(value.Trim()));
                }
                else if (string.Equals(key, "name", StringComparison.InvariantCultureIgnoreCase))
                {
                    column.Name = value.Trim();
                }
            }
        }

        private void ParseDisplayColumns(string displayFormat, out string[] displayNames, out Dictionary<string, int> displayDictKeys)
        {
            displayDictKeys = new Dictionary<string, int>();
            displayNames = null;
            if (string.IsNullOrEmpty(displayFormat))
            {
                return;
            }

            displayNames = displayFormat.Split('|');
            for (int i = 0; i < displayNames.Length - 1; i++)
            {
                if (displayNames[i].Contains(","))
                {
                    string[] token = displayNames[i].Split(',');
                    displayNames[i] = token[0].Trim();
                    displayDictKeys.Add(displayNames[i], int.Parse(token[1].Trim()));
                }
            }
        }

        #region 构造DataTable架构
        /// <summary>
        /// 以显示的列的架构构造出一个DataTable，如果显示列的架构为空，则返回null
        /// </summary>
        /// <returns></returns>
        public DataTable CreateDisplayColumnTable()
        {
            return CreateTableSchema(DisplayColumns, null);
        }

        /// <summary>
        /// 以显示的列的架构构造出一个DataTable，如果显示列的架构为空，则返回null
        /// </summary>
        /// <returns></returns>
        public DataTable CreateDisplayColumnTable(string[] columnNames)
        {
            return CreateTableSchema(DisplayColumns, columnNames);
        }

        /// <summary>
        /// 以导出的列的架构构造出一个DataTable，如导出列的架构为空，则返回null
        /// </summary>
        /// <returns></returns>
        public DataTable CreateExportColumnTable()
        {
            return CreateTableSchema(ExportColumns, null);
        }

        /// <summary>
        ///  以导出的列的架构构造出一个DataTable，如导出列的架构为空，则返回null
        /// </summary>
        /// <param name="columnNames"></param>
        /// <returns></returns>
        public DataTable CreateExportColumnTable(string[] columnNames)
        {
            return CreateTableSchema(ExportColumns, columnNames);
        }

        /// <summary>
        /// 构造DataTable的架构
        /// </summary>
        /// <param name="columns"></param>
        /// <param name="columnNames"></param>
        /// <returns></returns>
        private DataTable CreateTableSchema(List<ColumnInfo> columns, string[] columnNames)
        {
            if (columns == null)
            {
                return null;
            }

            DataTable dt = new DataTable();
            if (columnNames == null || columnNames.Length == 0)
            {
                foreach (ColumnInfo column in columns)
                {
                    var dataColumn = dt.Columns.Add(column.Name);
                    dataColumn.Caption = column.Caption;
                    dataColumn.DataType = typeof(string);
                }
            }
            else
            {
                foreach (string columnName in columnNames)
                {
                    foreach (ColumnInfo column in columns)
                    {
                        if (string.Equals(column.Name, columnName))
                        {
                            var dataColumn = dt.Columns.Add(column.Name);
                            dataColumn.Caption = column.Caption;
                            dataColumn.DataType = typeof(string);
                            break;
                        }
                    }
                }
            }

            return dt;
        }
        #endregion
    }
}
